using System;
using System.Collections.Generic;
using System.Text;
using ACS.Compiler.Tables;
using ACS.Compiler.Tables.Modes;
using ACS.Compiler.Tree.Interfaces;
using ACS.Compiler.Util;

namespace ACS.Compiler.Tree.Impl
{
    public class Select : Expression, IFinalIdent
    {
        private IExpression _left;
        private IExpression _right;

        private bool _leftIsNamespace = false;

        public override void MatchExpression(IExpression expression)
        {
            if (_left == null)
            {
                _left = expression;
            } else
            {
                _right = expression;
            }
        }

        public override void MatchSelect(Select select)
        {
            if (_left !=null)
            {
                MatchExpression(select);
            } else
            {
                Logger.Instance.TraceError("Select can be done from Ident or slice only."); 
            }
        }

        public override void MatchCall(Call call)
        {
            if (_left == null)
            {
                MatchExpression(call);
            } else
            {
                Logger.Instance.TraceError("Proc can't be selected"); 
            }
        }

        public override void MatchIdent(Ident ident)
        {
            MatchExpression(ident);
        }

        public IExpression Left
        {
            get { return _left; }
        }

        public IExpression Right
        {
            get { return _right; }
        }

        public override Expressions ExpressionType
        {
            get { return Expressions.Select; }
        }

        public override Mode Mode
        {
            get
            {
                return null;
            }
        }

        public override void Resolve(string ns, DataTable localData)
        {

        }

        public override string ToDeclareString()
        {
            if (_leftIsNamespace)
            {
                return Left.ToDeclareString() + ".Instance." + Right.ToDeclareString();
            } else
            {
                return Left.ToDeclareString() + "." + Right.ToDeclareString();
            }
        }

        public Mode ResolveIdent(string ns, DataTable localData, Mode parentMode)
        {
            if (parentMode == null)
            {
                switch (Left.ExpressionType)
                {
                    case Expressions.Ident:
                        Ident l1 = (Ident) Left;
                        if (Parser.FileParser.IsNamespace(l1.Name))
                        {
                            _leftIsNamespace = true;
                            Mode ret1 = ((IFinalIdent)Right).ResolveIdent(l1.Name, null, null);
                            if (ret1 == null)
                            {
                                Logger.Instance.TraceError("Type error.", this);
                            }
                            return ret1;
                        } else
                        {
                            goto case Expressions.Slice;
                        }
                    case Expressions.Slice:
                        IFinalIdent l = (IFinalIdent) Left;
                        Mode leftMode = l.ResolveIdent(ns, localData, parentMode);
                        Mode ret = ((IFinalIdent) Right).ResolveIdent(ns, localData, leftMode);
                        if (ret == null)
                        {
                            Logger.Instance.TraceError("Type error.", this);
                        }
                        return ret;
                    default:
                        Logger.Instance.TraceError("Type error.", this);
                        return null;
                }
            }
            else
            {
                ContainerMode parentContainer = parentMode as ContainerMode;
                if (parentContainer != null)
                {
                    Mode mode = Left.ModeResolveExpression(ns, localData, parentContainer);
                    mode = Right.ModeResolveExpression(ns, localData, mode);
                    return mode;
                } else
                {
                    Logger.Instance.TraceError("Wrong container type!", this);
                }
            }
            return null;
        }
    }
}
